<template>
  <div class="slot_main" :id="id">
    <div class="bar"
         v-if="initPageData.showBar&&(initPageData.bar.options.position==='left'||initPageData.bar.options.position==='top')"
         :style="initPageData.bar.style" v-show="barShow">
      <div :class="'barBtn'+index" style="position: relative;"
           v-for="(item,index) in initPageData.bar.options.buttonList" :style="initPageData.bar.options.buttonStyle"
           @click="show(item.name)" v-if="buttonShow(item.name)" @mouseover="barBtnMouseenter($event,index)"
           @mouseout="barBtnMouseout($event,index)" title="显示">
        <div style="cursor: inherit;position: absolute; top: 50%;left: 50%;transform: translate(-50%,-50%)"
             v-html="item.innerHTML?item.innerHTML:item.innerText"></div>
      </div>
    </div>

    <div :style="scrollBoxStyle">
      <div :class="initPageData.name+'_main_box'" class="main_box" :style="scrollContainerBoxStyle">

        <div v-for="(box,index) in boxList" v-show="index%2===0?!box.options.hide:lineShow(index-1)" :class="box.name"
             @pointerdown="resetSize($event,box.name)" :title="/^line/.test(box.name)&&'双击重置页面布局'"
             :style="box.style">
          <div v-if="/^line/.test(box.name)" title="按住可拖动"
               @pointerdown.stop="pointerdown($event,boxList[index-1].name)"
               :style="initPageData.line.controlButtonStyle"></div>
          <div :class="box.name+'_title'" :style="titleStyle" v-if="index%2===0&&box.options.showTitle">
            <div :style="initPageData.title.style" v-html="box.options.titleText?box.options.titleText:box.name">
            </div>
          </div>
          <div class="hideButton" title="隐藏"
               v-if="index%2===0&&box.options.showHideButton&&initPageData.showBar&&initPageData.hideButton"
               :style="initPageData.hideButton.style" v-show="hideButtonShow(box)" @click="hide(box.name)"
               v-html="initPageData.hideButton.options.innerHTML?initPageData.hideButton.options.innerHTML:initPageData.hideButton.options.innerText">
          </div>
          <slot v-if="index%2===0" :name="box.name" :init-page-data.sync="box.options.slot"></slot>
        </div>
      </div>
    </div>

    <div class="bar"
         v-if="initPageData.showBar&&(initPageData.bar.options.position==='right'||initPageData.bar.options.position==='bottom')"
         :style="initPageData.bar.style" v-show="barShow">
      <div v-for="(item,index) in initPageData.bar.options.buttonList" :style="initPageData.bar.options.buttonStyle"
           v-html="item.innerHTML?item.innerHTML:item.innerText" @click="show(item.name)" v-if="buttonShow(item.name)">
      </div>
    </div>
  </div>
</template>
<script>
  'use strict'
  const EventEmitter = require('events')
  const ResizeSensor = require('css-element-queries/src/ResizeSensor')

  const {util: {getRandomId}} = require('../util')
  export default {
    name: 'ResizeByDrag',
    data () {
      return {
        afterMounted: false,
        ev: new EventEmitter(),
        pageData: {},
        arr: [],
        scrollBoxStyle: {
          display: 'block',
          width: '100%',
          height: '100%',
          'vertical-align': 'top'
        },
        scrollContainerBoxStyle: {
          width: '100%',
          height: '100%'
        },
        slotBoxStyle: {},
        titleStyle: {
          width: `100%`,
          display: 'inline-block',
          overflow: 'hidden',
          'vertical-align': 'top',
          'font-size': '14px',
          'white-space': 'nowrap',
          'text-overflow': 'ellipsis'
        },
        id: getRandomId()
        // reset: false
      }
    },
    computed: {
      boxList () {
        console.group(`开始处理页面数据【${this.initPageData.name}】-boxList`)
        let boxList = []
        this.initPageData.slots.forEach((slot, index) => {
          boxList.push(slot)
          if (index !== this.initPageData.slots.length - 1) {
            boxList.push({
              name: `line_${this.initPageData.name}_${index}_${index + 1}`,
              style: this.initPageData.line.style,
              options: this.initPageData.line.options
            })
          }
        })
        console.log('数据处理完成')
        console.groupEnd()
        return boxList
      },
      barShow () {
        console.group('开始查询bar是否能够显示')
        if (!this.initPageData.showBar) {
          console.log('查询完成', '不被显示')
          console.groupEnd()
          return false
        }
        let isH =
          this.initPageData.bar.options.position === 'left' ||
          this.initPageData.bar.options.position === 'right'
        for (let slot of this.initPageData.slots) {
          if (slot.options.hide) {
            this.scrollBoxStyle[isH ? 'width' : 'height'] = `calc(100% - ${this.initPageData.bar.style[isH ? 'width' : 'height']})`
            console.log('查询完成', '显示')
            console.groupEnd()
            return true
          }
        }
        this.scrollBoxStyle[isH ? 'width' : 'height'] = '100%'
        console.log('查询完成', '隐藏')
        console.groupEnd()
        return false
      }
    },
    created () {
      console.group('------created------')
      this.initData()
      this.ev.on('hide', data => {
        let res = this.hide(data)
        this.ev.emit('reply', {type: 'hide', res, data})
      })
      this.ev.on('show', data => {
        let res = this.show(data)
        this.ev.emit('reply', {type: 'show', res, data})
      })
      console.groupEnd()
    },
    mounted () {
      console.group('------mounted------')
      this.$nextTick(() => {
        this.refreshBox()
        this.$nextTick(() => {
          this.reSize()
          this.$nextTick(() => {
            this.saveRatio()
          })
        })
        /* eslint-disable no-new */
        new ResizeSensor(document.querySelector(`#${this.id}`), () => {
          console.group(`【.${this.initPageData.name}_main_box】大小发生了变化`)
          this.$nextTick(this.reSize)
          console.groupEnd()
        })
        this.$emit('load', this.ev)
      })
      console.groupEnd()
    },
    methods: {
      resetSize (ev, name) {
        if (ev.pointerType === 'touch') return
        if (!/^line/.test(name)) return
        ev.stopPropagation()

        this.resetSize_count = this.resetSize_count || 1
        if (this.resetSize_count !== 2) {
          setTimeout(() => {
            this.resetSize_count = 0
          }, 300)
          return this.resetSize_count++
        }
        this.resetSize_count = 0

        // console.log('resetSize');
        this.$emit('resetSize')
        // this.reset = true;
        this.initData()

        this.$nextTick(() => {
          this.refreshBox()
          this.$nextTick(() => {
            this.reSize()
            this.$nextTick(() => {
              this.saveRatio()
            })
          })
        })
      },
      initData () {
        console.group('开始初始化数据')
        if (!this.initPageData.title) this.initPageData.title = {}
        if (!this.initPageData.title.style) this.initPageData.title.style = {}
        this.initPageData.title.style.overflow = 'hidden'
        this.initPageData.title.style['white-space'] = 'nowrap'
        this.initPageData.title.style['text-overflow'] = 'ellipsis'
        if (this.initPageData.hideButton) {
          if (!this.initPageData.hideButton.style) {
            this.initPageData.hideButton.style = {}
          }
          if (!this.initPageData.hideButton.options) {
            this.initPageData.hideButton.options = {}
          }
          this.initPageData.hideButton.style.display = 'inline-block'
          this.initPageData.hideButton.style.position = 'absolute'
          // this.initPageData.hideButton.style.top = '0';
          // this.initPageData.hideButton.style.right = '0';
          this.initPageData.hideButton.style['z-index'] = '9'
          this.titleStyle.width = `calc(100% - ${this.initPageData.hideButton.style.width} - 5px)`
          this.titleStyle['line-height'] = this.initPageData.hideButton.style.height
        }
        if (this.initPageData.showBar) {
          // 如果显示bar
          if (this.initPageData.bar.options.position === 'left' || this.initPageData.bar.options.position === 'right') {
            this.initPageData.bar.style.display = 'inline-block'
            this.scrollBoxStyle.display = 'inline-block'
            this.scrollBoxStyle.width = `calc(100% - ${this.initPageData.bar.style.width})`
            // 修改bar里面的按钮
            this.initPageData.bar.options.buttonStyle.display = 'block'
          } else {
            this.initPageData.bar.style.display = 'block'
            this.scrollBoxStyle.display = 'block'
            this.scrollBoxStyle.height = `calc(100% - ${this.initPageData.bar.style.height})`
            // 修改bar里面的按钮
            this.initPageData.bar.options.buttonStyle.display = 'inline-block'
          }
        }
        this.scrollBoxStyle[`overflow-${this.initPageData.isHorizontal ? 'x' : 'y'}`] = 'auto'
        this.scrollBoxStyle[`overflow-${this.initPageData.isHorizontal ? 'y' : 'x'}`] = 'hidden'
        this.initPageData.slots.forEach(slot => {
          slot.style.display = this.initPageData.isHorizontal ? 'inline-block' : 'block'
          slot.style.overflow = 'hidden'
          slot.style.position = 'relative'
        })
        delete this.initPageData.line.style.cursor
        this.initPageData.line.style.display = this.initPageData.isHorizontal ? 'inline-block' : 'block'
        this.initPageData.line.style.position = 'relative'
        this.scrollContainerBoxStyle[`min-${this.initPageData.isHorizontal ? 'width' : 'height'}`] = this.getSumMinSize() + this.getSumLineSize() + 'px'
        console.log('数据初始化完毕')
        console.groupEnd()
      },
      barBtnMouseenter (ev, index) {
        let el = document.querySelector('.barBtn' + index)
        if (!this.initPageData.bar.options.buttonHoverStyle) return
        for (let name in this.initPageData.bar.options.buttonHoverStyle) {
          el.style[name] = this.initPageData.bar.options.buttonHoverStyle[name]
        }
      },
      barBtnMouseout (ev, index) {
        let el = document.querySelector('.barBtn' + index)
        if (!this.initPageData.bar.options.buttonStyle) return
        for (let name in this.initPageData.bar.options.buttonStyle) {
          el.style[name] = this.initPageData.bar.options.buttonStyle[name]
        }
      },
      /**
       * 获取所有的显示的容器数组
       */
      getShowSlots () {
        // 获取所有显示的容器
        let tempList = []
        this.initPageData.slots.forEach(slot => {
          if (!slot.options.hide) tempList.push(slot)
        })
        return tempList
      },
      /**
       * 控制条是否显示
       * @param index 控制条的索引
       */
      lineShow (index) {
        // 如果前一个隐藏,则隐藏
        if (this.boxList[index].options.hide) return false
        let _index = this.getShowSlots().findIndex(slot => slot.name === this.boxList[index].name)
        // 判断该容器是不是显示容器的最后一个，如果是则隐藏控制条
        return _index !== this.getShowSlots().length - 1
      },
      /**
       * 获取所有容器的最小尺寸之和
       * @returns {number}
       */
      getSumMinSize () {
        let sumMinSize = 0
        this.initPageData.slots.forEach((slot, index) => {
          sumMinSize += this.getMinSize(slot.style)
        })
        return sumMinSize
      },
      /**
       * 获取所有控制条尺寸之和
       * @returns {number}
       */
      getSumLineSize () {
        return this.getSize(this.initPageData.line.style) * (this.initPageData.slots.length - 1)
      },
      /**
       * 获取主容器的有效尺寸
       * @returns {number}
       */
      getMainValidSize () {
        let mainDiv = document.querySelector(`#${this.id} .${this.initPageData.name}_main_box`)
        if (!mainDiv) return 0
        let mainSize = mainDiv[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight']
        let sumLineSize = (this.getShowSlots().length - 1) * this.getSize(this.initPageData.line.style)
        let sumMinSize = 0
        for (let i = 0; i < this.getShowSlots().length; i++) {
          sumMinSize += this.getMinSize(this.getShowSlots()[i].style)
        }
        return mainSize - sumMinSize - sumLineSize
      },
      hideButtonShow (slot) {
        let bigMainDiv = document.querySelector(`#${this.id}`)
        if (!bigMainDiv) return slot.options.showHideButton // 如果主容器不存在，隐藏
        if (this.getShowSlots().length === 1) return false // 如果只剩下一个盒子，隐藏
        return slot.options.showHideButton
      },
      buttonShow (slotName) {
        let slot = this.initPageData.slots.find(_slot => _slot.name === slotName)
        return slot ? slot.options.hide : false
      },
      pointerdown (ev, prevName) {
        if (ev.pointerType === 'touch') return
        // 获取在显示容器中的索引
        let _nextIndex = this.getShowSlots().findIndex(slot => slot.name === prevName) + 1
        let nextName = this.getShowSlots()[_nextIndex].name
        let prev = this.initPageData.slots.find(slot => slot.name === prevName) // 前一个元素
        let next = this.initPageData.slots.find(slot => slot.name === nextName) // 后一个元素

        let mPoint = {x: ev.screenX, y: ev.screenY} // 记录鼠标点击位置

        let prevSize = this.getSize(prev.style) // 记录前一个的大小
        let nextSize = this.getSize(next.style) // 记录后一个大小

        let div = document.createElement('div') // 创建遮罩层
        div.innerHTML = `<div id="mask" style="opacity:0;top:0;left:0;bottom: 0;right: 0;background-color:rgb(0,0,0);position:absolute;z-index:9999;cursor:${this.initPageData.isHorizontal ? 'col-resize' : 'row-resize'}"></div>`
        document.querySelector('body').appendChild(div.firstChild) // 向界面中添加遮罩
        let mask = document.getElementById('mask') // 获取遮罩
        const mouseup = ev => {
          mask.parentNode.removeChild(mask) // 去掉遮罩
          this.saveRatio()
        }
        const mouseout = ev => {
          mask.parentNode.removeChild(mask) // 去掉遮罩
          this.saveRatio()
        }
        const mousemove = ev => {
          // 遮罩的鼠标移动事件
          let x = ev.screenX - mPoint.x // 计算x的移动量
          let y = ev.screenY - mPoint.y // 计算y的移动量
          let prevMinSize = this.getMinSize(prev.style)
          let nextMinSize = this.getMinSize(next.style)

          let _prevSize = prevSize + (this.initPageData.isHorizontal ? x : y)
          let _nextSize = nextSize - (this.initPageData.isHorizontal ? x : y)

          if (_prevSize > prevMinSize && _nextSize > nextMinSize) {
            prev.style[this.initPageData.isHorizontal ? 'width' : 'height'] = _prevSize + 'px'
            next.style[this.initPageData.isHorizontal ? 'width' : 'height'] = _nextSize + 'px'
          } else if (_prevSize <= prevMinSize) {
            next.style[this.initPageData.isHorizontal ? 'width' : 'height'] = nextSize + prevSize - prevMinSize + 'px'
            prev.style[this.initPageData.isHorizontal ? 'width' : 'height'] = prevMinSize + 'px'
          } else if (_nextSize <= nextMinSize) {
            prev.style[this.initPageData.isHorizontal ? 'width' : 'height'] = nextSize + prevSize - nextMinSize + 'px'
            next.style[this.initPageData.isHorizontal ? 'width' : 'height'] = nextMinSize + 'px'
          }
        }

        mask.addEventListener('mouseup', mouseup)
        mask.addEventListener('mousemove', mousemove)
        mask.addEventListener('mouseout', mouseout)
      },
      getSize (style) {
        return parseFloat(style[this.initPageData.isHorizontal ? 'width' : 'height'].replace(/px/, ''))
      },
      getMinSize (style) {
        if (style[`min-${this.initPageData.isHorizontal ? 'width' : 'height'}`]) {
          return parseFloat(style[`min-${this.initPageData.isHorizontal ? 'width' : 'height'}`].replace(/px/, ''))
        }
        return 0
      },
      getBarSize () {
        if (!this.initPageData.showBar) return 0
        let barSize = 0
        let isH =
          this.initPageData.bar.options.position === 'left' ||
          this.initPageData.bar.options.position === 'right'
        // 如果容器水平放置，且bar也处于水平方向 或 容器垂直放置且bar、也处于垂直方向，就计算bar的尺寸
        if (
          (this.initPageData.isHorizontal && isH) ||
          (!this.initPageData.isHorizontal && !isH)
        ) {
          barSize = parseFloat(
            this.initPageData.bar.style[isH ? 'width' : 'height'].replace(
              /px/,
              ''
            )
          )
        }
        return barSize
      },
      getLineSize () {
        return this.getSize(this.initPageData.line.style)
      },
      show (slotName) {
        try {
          console.group('开始显示【' + slotName + '】')
          if (!slotName) return
          // 获取被操作容器的索引
          let index = this.initPageData.slots.findIndex(slot => slot.name === slotName)
          // 如果没有获取到索引，结束
          if (index === -1) return
          // 获取被操作容器
          let targetSlot = this.initPageData.slots[index]
          // 如果被操作的容器没有隐藏，结束
          if (!targetSlot.options.hide) return
          // 获取控制条的尺寸
          let lineSize = this.getSize(this.initPageData.line.style)
          // 获取变化的总尺寸（需要得到的大小）
          let targetSize = this.getSize(targetSlot.style)
          let minSize = this.getMinSize(targetSlot.style)

          let isLast = this.getShowSlots().length === this.initPageData.slots.length - 1

          // 最小宽度+bar-当前宽度的差值
          let deltaSize = 0
          let frameBox = document.querySelector(`#${this.id}`)
          if (frameBox[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight'] < this.getBarSize() + this.getMinSize(this.scrollContainerBoxStyle)) {
            deltaSize = this.getBarSize() + this.getMinSize(this.scrollContainerBoxStyle) - frameBox[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight']
            console.log(this.getBarSize(), this.getMinSize(this.scrollContainerBoxStyle), frameBox[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight'])
            if (deltaSize > this.getBarSize()) deltaSize = this.getBarSize()
          }
          console.log('deltaSize', deltaSize)
          let nextSlot = null
          console.log('开始寻找符合第一条件的容器:某个显示容器除去最小尺寸后剩余的尺寸还满足所需空间')
          let nextIndex = this.getSlotIndex(index, 'show1')
          if (nextIndex !== -1) {
            console.log('已找到符合第一条件的容器')
            nextSlot = this.initPageData.slots[nextIndex]
            // 下一个容器的新尺寸
            let newSize = this.getSize(nextSlot.style) - targetSize - lineSize
            if (isLast) newSize += this.getBarSize() - deltaSize
            nextSlot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = newSize + 'px'
            targetSlot.options.hide = false
            this.$emit('show', slotName)
            return true
          }

          console.log('没有找到符合第一条件的容器')

          console.log('开始寻找符合第二条件的容器:某个显示容器的尺寸大于控制线尺寸与这两个容器的最小尺寸之和')

          nextIndex = this.getSlotIndex(index, 'show2')
          if (nextIndex !== -1) {
            console.log('已找到符合第二条件的容器')
            nextSlot = this.initPageData.slots[nextIndex]
            // 获取显示容器的尺寸
            let nextSize = this.getSize(nextSlot.style)
            // 获取显示容器的最小尺寸
            let nextMinSize = this.getMinSize(nextSlot.style)

            let size = (nextSize - lineSize - nextMinSize - minSize) / 2
            if (isLast) size = (nextSize + this.getBarSize() - lineSize - nextMinSize - minSize) / 2
            targetSlot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = size + minSize + 'px'
            nextSlot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = size + nextMinSize + 'px'
            targetSlot.options.hide = false
            this.$emit('show', slotName)
            return true
          }

          console.log('没有找到符合第二条件的容器')
          console.log('进行最后的处理:切割其余容器，为该容器腾出最小尺寸空间')

          let sumSize = -this.getSize(this.initPageData.line.style)
          if (isLast) sumSize += this.getBarSize() - deltaSize

          let slotNames = []
          for (let slot of this.initPageData.slots) {
            if (slot.options.hide) continue // 如果容器已被隐藏则下一次循环
            sumSize += this.getSize(slot.style) - this.getMinSize(slot.style)
            slotNames.push(slot.name)
            // slot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = this.getMinSize(slot.style) + 'px';
            if (sumSize >= this.getMinSize(targetSlot.style)) {
              console.log('已得到符合条件的尺寸', sumSize, slot.name)
              break
            }
          }

          if (sumSize >= this.getMinSize(targetSlot.style)) {
            for (let _slotName of slotNames) {
              let _slot = this.initPageData.slots.find(slot => slot.name === _slotName)
              _slot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = this.getMinSize(_slot.style) + 'px'
            }
            targetSlot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = sumSize + 'px'
            targetSlot.options.hide = false

            this.$emit('show', slotName)
            return true
          }
        } finally {
          this.refreshLayout()
          console.log('【' + slotName + '】显示完成')
          console.groupEnd()
        }
      },
      /**
       * 隐藏容器
       * @param slotName 容器名称
       */
      hide (slotName) {
        try {
          console.group('开始隐藏【' + slotName + '】')
          if (!slotName) return
          // 获取隐藏容器的索引
          let index = this.initPageData.slots.findIndex(slot => slot.name === slotName)
          if (index === -1) return
          // 获取隐藏容器
          let targetSlot = this.initPageData.slots[index]
          // 如果该容器已被隐藏，退出
          if (targetSlot.options.hide) return
          // 获取下一个容器的索引
          let nextIndex = this.getSlotIndex(index, 'hide')
          // 获取下一个容器
          let nextSlot = this.initPageData.slots[nextIndex]
          if (!nextSlot) return console.groupEnd()
          // 计算出改变的尺寸（当前容器的尺寸+控制线的尺寸）
          let changeSize = this.getSize(targetSlot.style) + this.getSize(this.initPageData.line.style)
          let isFirst = this.getShowSlots().length === this.initPageData.slots.length
          // 如果这是隐藏的第一个容器，则改变的尺寸需要减去Bar的尺寸
          if (isFirst) {
            let scrollContainerBox = document.querySelector(`#${this.id} .${this.initPageData.name}_main_box`)
            if (scrollContainerBox.offsetWidth < this.getBarSize() + this.getMinSize(this.scrollContainerBoxStyle)) {
              changeSize +=
                this.getBarSize() +
                this.getMinSize(this.scrollContainerBoxStyle) -
                scrollContainerBox.offsetWidth
            }
            changeSize -= this.getBarSize()
          }
          // 设置下一个容器的尺寸（它自身的尺寸+改变的尺寸）
          nextSlot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = this.getSize(nextSlot.style) + changeSize + 'px'
          this.$set(targetSlot.options, 'hide', true)
          this.$emit('hide', slotName)
          return true
        } finally {
          console.log('【' + slotName + '】隐藏完成')
          console.groupEnd()

          this.refreshLayout()
        }
      },
      /**
       * 获取符合条件的slot索引
       * @param index 当前索引
       * @param type 类型
       * @param _index 目标索引
       * @returns {Number} slot索引
       */
      getSlotIndex (index, type, _index) {
        // 初始化 _index不存在且不为0
        if (!_index && _index !== 0) {
          // 如果当前操作容器不为最后一个
          if (index !== this.initPageData.slots.length - 1) {
            _index = index + 1
          } else {
            _index = index - 1
          }
        }
        // 是否显示
        let isShow = !this.initPageData.slots[_index].options.hide
        // 容器的尺寸
        let size = this.getSize(this.initPageData.slots[_index].style)
        // 容器的最小尺寸
        let minSize = this.getMinSize(this.initPageData.slots[_index].style)
        // 需要的尺寸
        let needSize = this.getSize(this.initPageData.slots[index].style)
        // 需要的最小尺寸
        let minNeedSize = this.getMinSize(this.initPageData.slots[index].style)
        // 控制条尺寸
        let lineSize = this.getSize(this.initPageData.line.style)
        // bar尺寸
        let barSize = this.getBarSize()
        // 是否为显示的最后一个
        let isLast = this.getShowSlots().length === this.initPageData.slots.length - 1
        // 是否为隐藏的第一个
        let isFirst = this.getShowSlots().length === this.initPageData.slots.length
        // 最小宽度+bar-当前宽度的差值
        let deltaSize = 0
        let frameBox = document.querySelector(`#${this.id}`)
        if (frameBox[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight'] < this.getBarSize() + this.getMinSize(this.scrollContainerBoxStyle)) {
          deltaSize = this.getBarSize() + this.getMinSize(this.scrollContainerBoxStyle) - frameBox[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight']
          if (deltaSize > this.getBarSize()) deltaSize = this.getBarSize()
        }

        let isTrue = isShow
        if (type === 'hide') {
          // 隐藏
          // 如果是第一个且bar比腾出来的空间大
          if (isFirst && needSize + lineSize < barSize) {
            console.log('bar尺寸大于隐藏容器尺寸与line尺寸之和')
            isTrue = isShow && size - minSize >= barSize - (needSize + lineSize)
          }
        } else if (type === 'show1') {
          // 显示方案1
          // 容器显示且容器尺寸减去最小尺寸大于需要的尺寸
          isTrue = isShow && size - minSize >= needSize + lineSize
          if (isLast) isTrue = isShow && size + barSize - minSize >= needSize + lineSize - deltaSize
        } else if (type === 'show2') {
          // 显示方案2
          // 容器显示且容器尺寸减去两者最小尺寸还大于line尺寸
          isTrue = isShow && size - minSize - minNeedSize >= lineSize
          if (isLast) isTrue = isShow && size + barSize - minSize - minNeedSize >= lineSize - deltaSize
        }

        if (isTrue) {
          return _index
        } else {
          if (_index === 0 || (index === 0 && _index === this.initPageData.slots.length - 1)) {
            return -1
          } else if (_index === this.initPageData.slots.length - 1) {
            return this.getSlotIndex(index, type, index - 1)
          } else if (_index > index) {
            return this.getSlotIndex(index, type, _index + 1)
          } else if (_index < index) return this.getSlotIndex(index, type, _index - 1)
        }
      },
      reSize () {
        try {
          console.group(`根据比例调整页面【${this.initPageData.name}】`)
          if (!this.getMainValidSize()) {
            for (let slot of this.initPageData.slots) {
              if (slot.options.hide) continue
              slot.style[this.initPageData.isHorizontal ? 'width' : 'height'] =
                this.getMinSize(slot.style) + 'px'
            }
            console.log(
              '调整页面完成:',
              '当前尺寸小于最小尺寸，所有容器为最小值'
            )
            return
          }

          for (let slot of this.initPageData.slots) {
            if (slot.options.hide) continue
            slot.style[this.initPageData.isHorizontal ? 'width' : 'height'] =
              this.getMainValidSize() * slot.options.ratio +
              this.getMinSize(slot.style) +
              'px'
          }
        } finally {
          console.log('调整页面完成')
          console.groupEnd()
        }
      },
      saveRatio () {
        try {
          console.group(`获取【${this.initPageData.name}】并保存比例`)
          if (!this.getMainValidSize()) {
            console.log('当前已是最小宽度，不用保存比例')
            return
          }
          for (let slot of this.initPageData.slots) {
            if (slot.options.hide) {
              slot.options.ratio = 0
              // console.log(slot.name, slot.options.ratio)
              continue
            }
            let slotMainBox = document.querySelector(`#${this.id} .${this.initPageData.name}_main_box .${slot.name}`)
            if (!slotMainBox) continue
            let slotMainBoxSize = slotMainBox[this.initPageData.isHorizontal ? 'offsetWidth' : 'offsetHeight']
            slot.style[this.initPageData.isHorizontal ? 'width' : 'height'] = slotMainBoxSize + 'px'
            slot.options.ratio = (slotMainBoxSize - this.getMinSize(slot.style)) / this.getMainValidSize()
            // console.log(slot.name, slot.options.ratio)
          }
          console.log('保存比例完成')
        } finally {
          this.$emit('resize')
          console.groupEnd()
        }
      },
      /**
       * 调整容器的尺寸
       */
      refreshBox () {
        console.group('refreshBox')
        this.getShowSlots().forEach(slot => {
          let box = document.querySelector(`#${this.id} .${this.initPageData.name}_main_box .${slot.name}`)
          if (!box) return
          for (let i = 0; i < box.children.length; i++) {
            if (box.children[i].className !== `${slot.name}_title` && box.children[i].className !== 'hideButton') {
              if (!slot.options.showTitle) {
                box.children[i].style.height = `100%`
              } else {
                box.children[i].style.height = `calc(100% - ${box.children[0].offsetHeight}px)`
              }
            }
          }
        })
        console.groupEnd()
      },
      isShow (slotName) {
        if (!slotName) return
        let index = this.initPageData.slots.findIndex(slot => slot.name === slotName)
        if (index === -1) return
        let targetSlot = this.initPageData.slots[index]
        return !targetSlot.options.hide
      },
      /**
       * 交换两个容器的尺寸
       * @param slotName1 要显示的容器名
       * @param slotName2 要隐藏的容器名
       */
      exchange (slotName1, slotName2) {
        if (!slotName1 || !slotName2) return
        let index1 = this.initPageData.slots.findIndex(slot => slot.name === slotName1)
        if (index1 === -1) return
        let index2 = this.initPageData.slots.findIndex(slot => slot.name === slotName2)
        if (index2 === -1) return

        let slot1 = this.initPageData.slots[index1]
        let slot2 = this.initPageData.slots[index2]
        let isTrue = this.isShow(slotName2)
        let minSize1 = this.getMinSize(slot1.style)
        let minSize2 = this.getMinSize(slot2.style)
        let size1 = this.getSize(slot1.style)
        let size2 = this.getSize(slot2.style)

        // 显示时需要的最小区域小于等于要隐藏的区域 且 隐藏区域的最小尺寸小于等于要显示区域的尺寸
        if (isTrue && minSize1 <= size2 && minSize2 <= size1) {
          slot1.style[this.initPageData.isHorizontal ? 'width' : 'height'] =
            size2 + 'px'
          slot2.style[this.initPageData.isHorizontal ? 'width' : 'height'] =
            size1 + 'px'
          slot1.options.hide = false
          slot2.options.hide = true

          this.refreshLayout()
        } else if (isTrue && minSize1 <= size2) {
          slot1.style[this.initPageData.isHorizontal ? 'width' : 'height'] =
            size2 + 'px'
          slot2.style[this.initPageData.isHorizontal ? 'width' : 'height'] =
            minSize2 + 'px'
          slot1.options.hide = false
          slot2.options.hide = true

          this.refreshLayout()
        } else {
          // 显示时需要的最小区域大于要隐藏的区域
          this.hide(slotName2)
          this.show(slotName1)
        }
      },
      refreshLayout () {
        this.$nextTick(() => {
          this.saveRatio()
          this.refreshBox()
          this.$nextTick(() => {
            this.reSize()
          })
        })
      }
    },
    props: {
      initPageData: {
        type: Object,
        default: () => {
          return {}
        },
        validator: value => {
          // console.log(`开始验证数据【${value.name}】`);
          if (!value.name || typeof value.name !== 'string') {
            throw new Error('未找到name属性')
          }
          if (value.showBar) {
            if (!value.bar || typeof value.bar !== 'object') {
              throw new Error('未找到bar属性，或bar属性类型不正确')
            }
            if (!value.bar.style || typeof value.bar.style !== 'object') {
              throw new Error('未找到bar.style属性，或bar.style属性类型不正确')
            }
            if (!value.bar.options || typeof value.bar.options !== 'object') {
              throw new Error(
                '未找到bar.options属性，或bar.options属性类型不正确'
              )
            }
            if (
              !value.bar.options.buttonList ||
              typeof value.bar.options.buttonList !== 'object'
            ) {
              throw new Error(
                '未找到bar.options.buttonList属性，或bar.options.buttonList属性类型不正确'
              )
            }
            if (
              !value.bar.options.buttonStyle ||
              typeof value.bar.options.buttonStyle !== 'object'
            ) {
              throw new Error(
                '未找到bar.options.buttonStyle属性，或bar.options.buttonStyle属性类型不正确'
              )
            }
            if (
              !value.bar.options.position ||
              typeof value.bar.options.position !== 'string'
            ) {
              throw new Error(
                '未找到bar.options.position属性，或bar.options.position属性类型不正确'
              )
            }
          }
          if (!value.line || typeof value.line !== 'object') {
            throw new Error('未找到line属性，或line属性类型不正确')
          }
          if (!value.line.style || typeof value.line.style !== 'object') {
            throw new Error('未找到line.style属性，或line.style属性类型不正确')
          }
          if (!value.line.options || typeof value.line.options !== 'object') {
            throw new Error(
              '未找到line.options属性，或line.options属性类型不正确'
            )
          }
          if (value.title && typeof value.title !== 'object') {
            throw new Error('未找到title属性，或title属性类型不正确')
          }

          if (!value.slots || typeof value.slots !== 'object') {
            throw new Error('未找到slots属性，或slots属性类型不正确')
          }

          for (let slot of value.slots) {
            if (!slot.name || typeof slot.name !== 'string') {
              throw new Error(
                'slots数组内，未找到name属性，或name属性类型不正确'
              )
            }
            if (!slot.style || typeof slot.style !== 'object') {
              throw new Error(
                'slots数组内，未找到style属性，或style属性类型不正确'
              )
            }
            if (!slot.options || typeof slot.options !== 'object') {
              throw new Error(
                'slots数组内，未找到options属性，或options属性类型不正确'
              )
            }
            if (
              value.showBar &&
              slot.options.showHideButton &&
              (!value.hideButton || typeof value.hideButton !== 'object')
            ) {
              throw new Error('未找到hideButton属性，或hideButton属性类型不正确')
            }
          }
          // console.log(`数据验证通过【${value.name}】`);
          // if (ev) ev.emit('init');

          return true
        }
      }
    }
  }
</script>

<style scoped>
  .slot_main {
    width: 100%;
    height: 100%;
    font-size: 0;
    overflow: auto;
  }

  /**
     * 滚动条样式
     */
  .scroll_bar::-webkit-scrollbar-thumb {
    background-color: #c2c7ce;
    border-radius: 4px;
  }

  .scroll_bar::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  .bar {
    font-size: 14px;
  }

  .slot_main * {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    cursor: default;
  }

  .main_box div {
    font-size: 0;
  }

  .main_box div * {
    /*font-size: 14px;*/
  }
</style>
